﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
/// <summary>
/// 话说这个不用接口,直接写个普通的类不行吗? 让子类去用泛型,父类就用来
/// </summary>
public interface IEventInfo
{

}
/// <summary>
/// 这个EventInfo就是封装了一下UnityAction, 在字典里value填的它, 但是实际上后面方法用的都是它里面唯一的字段actions , 就为了能用个泛型折腾了这么个类
/// </summary>
/// <typeparam name="T"></typeparam>
public class EventInfo<T>:IEventInfo
{
    public UnityAction<T> actions;
    public EventInfo(UnityAction<T> action)
    {
        actions += action;
    }
}
/// <summary>
/// 这个就是为了下边事件中心方法重载专门创建的类, 为了能让那个方法既能传入有参委托也能传入无参委托
/// </summary>
public class EventInfo : IEventInfo
{
    public UnityAction actions;
    public EventInfo(UnityAction action)
    {
        actions += action;
    }
}

///<summary>
///事件中心
///</summary>
public class EventCenter : BaseManager<EventCenter>
{
    //key - 事件名字
    //value - 监听这个事件的委托
    //这里的value的类型是自定义的,IEventInfo, 是为了避免拆装箱才这么整的 , 大概就是value和方法都要用泛型, 但是如果他们用泛型的话 , 整个类就必须是泛型类, 但是咱们家EventCenter单例类只能实例化一次,如果用了泛型 , 第一次使用时就确定了类型,使用泛型也没意义了
    private Dictionary<string, IEventInfo> eventDic = new Dictionary<string, IEventInfo>();
    /// <summary>
    /// 添加事件监听(事件注册) , 
    /// </summary>
    /// <param name="name"></param>
    /// <param name="action"></param>
    public void AddEventListener<T>(string name , UnityAction<T> action)
    {
        //如果有对应的事件则加入委托 , 如果没有就创建字典key , 然后存入委托
        if(eventDic.ContainsKey(name))
        { //这个eventDic[name]可不是UnityAction类型的, 你看下边else里的代码, 存的就是那个玩意, 也就是存着的是EventInfo类的对象的引用
            //并且, 由于字典里value是用的IEventInfo , 所以实际上是用父类存的子类, eventDic[name] 实际上是IEventInfo类型, 所以调用actions时还需要转一下类型
            (eventDic[name] as EventInfo<T>).actions += action;
        }
        else
        {
            eventDic.Add(name, new EventInfo<T>(action));
        }

    }
    /// <summary>
    /// 上边那个函数的重载, 监听不需要传参的事件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="name"></param>
    /// <param name="action"></param>
    public void AddEventListener(string name, UnityAction action)
    {
        //如果有对应的事件则加入委托 , 如果没有就创建字典key , 然后存入委托
        if (eventDic.ContainsKey(name))
        {
            (eventDic[name] as EventInfo).actions += action;
        }
        else
        {
            eventDic.Add(name, new EventInfo(action));
        }

    }
    /// <summary>
    /// 事件触发(委托队列调用) , 我是被注册的事件,当我发生后就执行这个函数来 , 来实现委托队列的执行 , name就是这个事件名, info就是传递来的信息, 毕竟也许是需要传参数的
    /// </summary>
    /// <param name="name"></param>
    /// <param name="info"></param>
    public void EventTrigger<T>(string name, T info)
    {
        if(eventDic.ContainsKey(name))
        {
            if((eventDic[name] as EventInfo<T>).actions!=null)
            {
                (eventDic[name] as EventInfo<T>).actions.Invoke(info);
            }
          
        }
    }
    /// <summary>
    /// 这个是上边方法的重载, 无参版本
    /// </summary>
    /// <param name="name"></param>
    /// <param name="info"></param>
    public void EventTrigger(string name)
    {
        if (eventDic.ContainsKey(name))
        {
            if ((eventDic[name] as EventInfo).actions != null)
            {
                (eventDic[name] as EventInfo).actions.Invoke();
            }

        }
    }
    /// <summary>
    /// 有加就有减, 某些情况下, 本来监控某个事件的对象可能就不再监控了, 比如某个对象Destroy前就应该remove掉他对某些事件的监控
    /// </summary>
    /// <param name="name"></param>
    /// <param name="action"></param>
    public void RemoveEventListener(string name,UnityAction action)
    {
        if(eventDic.ContainsKey(name))
        {
            (eventDic[name] as EventInfo).actions -= action;
        }
    }
    /// <summary>
    /// 在某些时候需要清空事件, 比如转场景
    /// </summary>
    public void Clear()
    {
        eventDic.Clear();
    }
}
